package org.thirdHero.wx.service.impl;

import com.alibaba.fastjson.JSON;
import com.github.binarywang.wxpay.bean.WxPayApiData;
import com.github.binarywang.wxpay.bean.request.WxPayBaseRequest;
import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest;
import com.github.binarywang.wxpay.bean.result.WxPayBaseResult;
import com.github.binarywang.wxpay.bean.result.WxPayUnifiedOrderResult;
import com.github.binarywang.wxpay.config.WxPayConfig;
import com.github.binarywang.wxpay.constant.WxPayConstants;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.impl.WxPayServiceAbstractImpl;
import com.github.binarywang.wxpay.util.SignUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.thirdHero.core.util.FastJsonUtil;
import org.thirdHero.wx.constant.WxProFitSharingConstant;
import org.thirdHero.wx.request.WxPayUnifiedOrderSharingRequest;
import org.thirdHero.wx.request.WxProfitSharingAddReceiverRequest;
import org.thirdHero.wx.request.WxProfitSharingRequest;
import org.thirdHero.wx.response.WxProfitSharingAddReceiverResult;
import org.thirdHero.wx.response.WxProfitSharingResult;
import org.thirdHero.wx.service.WxSharingService;

import java.util.HashMap;
import java.util.Map;

/**
 * <pre>
 * 微信分账请求实现类
 * Created by Binary Wang on 2016/7/28.
 * </pre>
 *
 * @author thirdHero
 */
public abstract class WxSharingServiceImpl extends WxPayServiceAbstractImpl implements WxSharingService {
    private static final String PAY_BASE_URL = "https://api.mch.weixin.qq.com";
    protected final Logger log = LoggerFactory.getLogger(this.getClass());
    protected static ThreadLocal<WxPayApiData> wxApiData = new ThreadLocal<>();

    protected WxPayConfig config;

    private String getPayBaseUrl() {
        if (this.getConfig().useSandbox()) {
            return PAY_BASE_URL + "/sandboxnew";
        }

        return PAY_BASE_URL;
    }
    /**
     * 发送post请求
     *
     * @param url        请求地址
     * @param requestStr 请求信息
     * @param useKey     是否使用证书
     * @return 返回请求结果字符串
     */
    protected abstract String post(String url, String requestStr, boolean useKey) throws WxPayException;

    @Override
    public WxPayConfig getConfig() {
        return this.config;
    }

    @Override
    public void setConfig(WxPayConfig config) {
        this.config = config;
    }


    @Override
    public WxProfitSharingAddReceiverResult profitSharingAddReceiver(WxProfitSharingAddReceiverRequest request) throws WxPayException {
        request.checkAndSign(this.getConfig());
        String url = this.getPayBaseUrl() + "/pay/profitsharingaddreceiver";
        String xml = request.toXML();
        if(xml.contains(WxProFitSharingConstant.CDATA_PREFIX)){
            xml = xml.replace(WxProFitSharingConstant.CDATA_PREFIX, "")
                    .replace(WxProFitSharingConstant.CDATA_SUFFIX, "");
        }
        String responseContent = this.post(url, xml,false);
        WxProfitSharingAddReceiverResult result = WxPayBaseResult.fromXML(responseContent, WxProfitSharingAddReceiverResult.class);
        result.setSignType(WxPayConstants.SignType.HMAC_SHA256);
        result.checkResult(this);
        return result;
    }

    /**
     * 单次分账请求按照传入的分账接收方账号和资金进行分账，同时会将订单剩余的待分账金额解冻给本商户。故操作成功后，订单不能再进行分账，也不能进行分账完结。
     * @param request
     * @return
     * @throws WxPayException
     */
    @Override
    public WxProfitSharingResult profitSharing(WxProfitSharingRequest request) throws WxPayException {
        request.checkAndSign(this.getConfig());
        String url = this.getPayBaseUrl() + "/secapi/pay/profitsharing";
        String xml = request.toXML();
        if(xml.contains(WxProFitSharingConstant.CDATA_PREFIX)){
            xml = xml.replace(WxProFitSharingConstant.CDATA_PREFIX, "")
                    .replace(WxProFitSharingConstant.CDATA_SUFFIX, "");
        }
        String responseContent = this.post(url, xml, true);
        WxProfitSharingResult result = WxPayBaseResult.fromXML(responseContent,WxProfitSharingResult.class);
        result.setSignType(WxPayConstants.SignType.HMAC_SHA256);
        result.checkResult(this);
        return result;
    }
    @Override
    public WxPayUnifiedOrderResult unifiedOrder(WxPayUnifiedOrderSharingRequest request) throws WxPayException {
        request.checkAndSign(this.getConfig());

        String url = this.getPayBaseUrl() + "/pay/unifiedorder";
        String responseContent = this.post(url, request.toXML(), false);
        WxPayUnifiedOrderResult result = WxPayBaseResult.fromXML(responseContent, WxPayUnifiedOrderResult.class);
        result.checkResult(this);
        return result;
    }
    @Override
    public Map<String, String> getPayInfo(WxPayUnifiedOrderSharingRequest request) throws WxPayException {
        WxPayUnifiedOrderResult unifiedOrderResult = this.unifiedOrder(request);
        String prepayId = unifiedOrderResult.getPrepayId();
        if (StringUtils.isBlank(prepayId)) {
            throw new RuntimeException(String.format("无法获取prepay id，错误代码： '%s'，信息：%s。",
                    unifiedOrderResult.getErrCode(), unifiedOrderResult.getErrCodeDes()));
        }

        Map<String, String> payInfo = new HashMap<>();
        String timestamp = String.valueOf(System.currentTimeMillis() / 1000);
        String nonceStr = String.valueOf(System.currentTimeMillis());
        if (WxPayConstants.TradeType.NATIVE.equals(request.getTradeType())) {
            payInfo.put("codeUrl", unifiedOrderResult.getCodeURL());
        } else if (WxPayConstants.TradeType.APP.equals(request.getTradeType())) {
            // APP支付绑定的是微信开放平台上的账号，APPID为开放平台上绑定APP后发放的参数
            String appId = getConfig().getAppId();
            Map<String, String> configMap = new HashMap<>();
            // 此map用于参与调起sdk支付的二次签名,格式全小写，timestamp只能是10位,格式固定，切勿修改
            String partnerId = getConfig().getMchId();
            configMap.put("prepayid", prepayId);
            configMap.put("partnerid", partnerId);
            String packageValue = "Sign=WXPay";
            configMap.put("package", packageValue);
            configMap.put("timestamp", timestamp);
            configMap.put("noncestr", nonceStr);
            configMap.put("appid", appId);
            // 此map用于客户端与微信服务器交互
            payInfo.put("sign", SignUtils.createSign(configMap, this.getConfig().getMchKey(), null));
            payInfo.put("prepayId", prepayId);
            payInfo.put("partnerId", partnerId);
            payInfo.put("appId", appId);
            payInfo.put("packageValue", packageValue);
            payInfo.put("timeStamp", timestamp);
            payInfo.put("nonceStr", nonceStr);
        } else if (WxPayConstants.TradeType.JSAPI.equals(request.getTradeType())) {
            payInfo.put("appId", unifiedOrderResult.getAppid());
            // 支付签名时间戳，注意微信jssdk中的所有使用timestamp字段均为小写。但最新版的支付后台生成签名使用的timeStamp字段名需大写其中的S字符
            payInfo.put("timeStamp", timestamp);
            payInfo.put("nonceStr", nonceStr);
            payInfo.put("package", "prepay_id=" + prepayId);
            payInfo.put("signType", WxPayConstants.SignType.MD5);
            payInfo.put("paySign", SignUtils.createSign(payInfo, this.getConfig().getMchKey(), null));
        }

        return payInfo;
    }
}
